// Magic Software, Inc.
// http://www.magic-software.com
// Copyright (c) 2000, All Rights Reserved
//
// Source code from Magic Software is supplied under the terms of a license
// agreement and may not be copied or disclosed except in accordance with the
// terms of that agreement.  The various license agreements may be found at
// the Magic Software web site.  This file is subject to the license
//
// RESTRICTED USE SOURCE CODE
// http://www.magic-software.com/License/restricted.pdf

#include "MgcRenderer.h"
#include "MgcTriMesh.h"

MgcImplementRTTI(MgcTriMesh,MgcGeometry);
MgcImplementStream(MgcTriMesh);

//---------------------------------------------------------------------------
MgcTriMesh::MgcTriMesh (unsigned int uiVertexQuantity, MgcVector3* akVertex,
    MgcVector3* akNormal, MgcColor* akColor, MgcVector2* akTexture,
    unsigned int uiTriangleQuantity, unsigned int* auiConnect)
    :
    MgcGeometry(uiVertexQuantity,akVertex,akNormal,akColor,akTexture)
{
    m_uiTriangleQuantity = uiTriangleQuantity;
    m_auiConnect = auiConnect;
}
//---------------------------------------------------------------------------
MgcTriMesh::MgcTriMesh ()
{
    m_uiTriangleQuantity = 0;
    m_auiConnect = 0;
}
//---------------------------------------------------------------------------
MgcTriMesh::~MgcTriMesh ()
{
    delete[] m_auiConnect;
}
//---------------------------------------------------------------------------
void MgcTriMesh::Reconstruct (unsigned int uiVertexQuantity,
    unsigned int uiTriangleQuantity)
{
    MgcGeometry::Reconstruct(uiVertexQuantity);

    m_uiTriangleQuantity = uiTriangleQuantity;
    delete[] m_auiConnect;
    if ( m_uiTriangleQuantity > 0 )
        m_auiConnect = new unsigned int[3*m_uiTriangleQuantity];
}
//---------------------------------------------------------------------------
void MgcTriMesh::Reconstruct (unsigned int uiVertexQuantity,
    MgcVector3* akVertex, MgcVector3* akNormal, MgcColor* akColor,
    MgcVector2* akTexture, unsigned int uiTriangleQuantity,
    unsigned int* auiConnect)
{
    MgcGeometry::Reconstruct(uiVertexQuantity,akVertex,akNormal,akColor,
        akTexture);

    if ( m_auiConnect != auiConnect )
    {
        delete[] m_auiConnect;
        m_auiConnect = auiConnect;
    }

    m_uiTriangleQuantity = uiTriangleQuantity;
}
//---------------------------------------------------------------------------
void MgcTriMesh::GetTriangle (unsigned int uiT, unsigned int& ruiV0,
    unsigned int& ruiV1, unsigned int& ruiV2) const
{
    assert( uiT < m_uiTriangleQuantity );

    unsigned int uiBase = 3*uiT;
    ruiV0 = m_auiConnect[uiBase];
    ruiV1 = m_auiConnect[uiBase+1];
    ruiV2 = m_auiConnect[uiBase+2];
}
//---------------------------------------------------------------------------
void MgcTriMesh::GetTriangle (unsigned int uiT, MgcVector3& rkV0,
    MgcVector3& rkV1, MgcVector3& rkV2) const
{
    assert( uiT < m_uiTriangleQuantity );

    unsigned int uiBase = 3*uiT;
    rkV0 = m_akVertex[m_auiConnect[uiBase]];
    rkV1 = m_akVertex[m_auiConnect[uiBase+1]];
    rkV2 = m_akVertex[m_auiConnect[uiBase+2]];
}
//---------------------------------------------------------------------------
void MgcTriMesh::UpdateModelNormals ()
{
    // Calculate normals from vertices by weighted averages of facet planes
    // that contain the vertices.  TO DO.  Replace by algorithm that computes
    // axis of minimum cone containing the normals.

    if ( !m_akNormal )
        m_akNormal = new MgcVector3[m_uiVertexQuantity];

    memset(m_akNormal,0,m_uiVertexQuantity*sizeof(MgcVector3));

    unsigned int* auiConnect = m_auiConnect;
    for (unsigned int uiT = 0; uiT < m_uiTriangleQuantity; uiT++)
    {
        // get vertex indices
        unsigned int uiV0 = *auiConnect++;
        unsigned int uiV1 = *auiConnect++;
        unsigned int uiV2 = *auiConnect++;

        // get vertices
        MgcVector3& rkV0 = m_akVertex[uiV0];
        MgcVector3& rkV1 = m_akVertex[uiV1];
        MgcVector3& rkV2 = m_akVertex[uiV2];

        // compute the normal (length provides the weighted sum)
        MgcVector3 kEdge1 = rkV1 - rkV0;
        MgcVector3 kEdge2 = rkV2 - rkV0;
        MgcVector3 kNormal = kEdge1.Cross(kEdge2);

        m_akNormal[uiV0] += kNormal;
        m_akNormal[uiV1] += kNormal;
        m_akNormal[uiV2] += kNormal;
    }

    for (unsigned int uiV = 0; uiV < m_uiVertexQuantity; uiV++)
        m_akNormal[uiV].Unitize();
}
//---------------------------------------------------------------------------
void MgcTriMesh::Draw (MgcRenderer& rkRenderer)
{
    MgcGeometry::Draw(rkRenderer);
    rkRenderer.Draw(*this);
}
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// streaming
//---------------------------------------------------------------------------
MgcObject* MgcTriMesh::Factory (MgcStream& rkStream)
{
    MgcTriMesh* pkObject = new MgcTriMesh;
    MgcStream::Link* pkLink = new MgcStream::Link(pkObject);
    pkObject->Load(rkStream,pkLink);
    return pkObject;
}
//---------------------------------------------------------------------------
void MgcTriMesh::Load (MgcStream& rkStream, MgcStream::Link* pkLink)
{
    MgcGeometry::Load(rkStream,pkLink);

    // native data
    MgcStreamRead(rkStream,m_uiTriangleQuantity);
    unsigned int uiQuantity = 3*m_uiTriangleQuantity;
    m_auiConnect = new unsigned int[uiQuantity];
    MgcStreamRead(rkStream,m_auiConnect,uiQuantity);
}
//---------------------------------------------------------------------------
void MgcTriMesh::Link (MgcStream& rkStream, MgcStream::Link* pkLink)
{
    MgcGeometry::Link(rkStream,pkLink);
}
//---------------------------------------------------------------------------
bool MgcTriMesh::Register (MgcStream& rkStream)
{
    return MgcGeometry::Register(rkStream);
}
//---------------------------------------------------------------------------
void MgcTriMesh::Save (MgcStream& rkStream)
{
    MgcGeometry::Save(rkStream);

    // native data
    MgcStreamWrite(rkStream,m_uiTriangleQuantity);
    MgcStreamWrite(rkStream,m_auiConnect,3*m_uiTriangleQuantity);
}
//---------------------------------------------------------------------------
